package com.example.zselasticsearchsf.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.zselasticsearchsf.common.CommonResult;
import com.example.zselasticsearchsf.config.SearchUtil;
import com.example.zselasticsearchsf.config.es.request.CoreSearchReqDto;
import com.example.zselasticsearchsf.config.es.request.GeoBoundingBoxEntity;
import com.example.zselasticsearchsf.config.es.request.SearchReqDto;
import com.example.zselasticsearchsf.config.es.respons.SearchRepDto;
import com.example.zselasticsearchsf.domain.CaseInfoBean;
import com.example.zselasticsearchsf.domain.User;
import com.example.zselasticsearchsf.dto.SfwDto;
import io.swagger.annotations.ApiOperation;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

import static org.elasticsearch.index.query.QueryBuilders.matchQuery;

/**
 * @Author: Steven
 * @Date: 2021/10/25 9:14
 */
@RestController
@RequestMapping("zs/search")
public class SerachController {

    @Autowired
    @Qualifier(value = "restHighLevelClient")
    private RestHighLevelClient client;

    @Resource
    private SearchUtil searchUtil;


    /**
     * 关键词【高亮查询】7.14.x
     */
    @GetMapping("/highLightMatch")
    public CommonResult<Map<String, Object>> highLightMatch(@RequestParam(value = "keywords", required = false) String keywords,
                                                            @RequestParam(value = "page", required = false) Integer page,
                                                            @RequestParam(value = "size", required = false) Integer size) {

        if (keywords == null) {
            keywords = "";
        }
        if (page == null) {
            page = 1;
        }
        if (size == null) {
            size = 10;
        }
        // 1.构建QueryBuilder对象指定查询方式
        QueryBuilder queryBuilder = matchQuery("caseTittlDateUtilse", keywords);

        // 2.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest("sfw");

        // 3.构建SearchSourceBuilder查询对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 4.将QueryBuilder对象设置到SearchSourceBuilder中
        sourceBuilder.query(queryBuilder);
        /**
         *  from：当前页起始索引  从0开始 int from = (pageNum - 1) * size;
         *  size：每页显示多少条
         */
        sourceBuilder.size(size);
        sourceBuilder.from((page - 1) * size);
        sourceBuilder.trackTotalHits(true);
        /**
         * 通过sort方法指定排序规则
         * 第一个参数：排序字段
         * 第二个参数：升序还是降序(可以不填写，默认升序)
         */
//        sourceBuilder.sort("submissionTime", SortOrder.DESC);
//        sourceBuilder.sort("visits", SortOrder.DESC);

        // 5构建HighlightBuilder高亮对象
        HighlightBuilder highlightBuilder = new HighlightBuilder();

        // 5.1设置要高亮的字段
        highlightBuilder.field("caseTittlDateUtilse");

        // 5.2设置高亮样式
//        highlightBuilder.preTags("<font color='pink';font-weight: 700' >");
//        highlightBuilder.postTags("</font>");
//                highlightBuilder.preTags("<span style=\"color:pink\" >");
//        highlightBuilder.postTags("</span>");
        highlightBuilder.preTags("<span style='color:red;'>");
        highlightBuilder.postTags("</span>");
        // 6.将高亮对象highlightBuilder设置到sourceBuilder中
        sourceBuilder.highlighter(highlightBuilder);

        // 7.将SearchSourceBuilder查询对象封装到请求对象SearchRequest中
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = null;

        List<SfwDto> sfwDtoArrayList = new ArrayList<>();
        Map<String, Object> res = new HashMap<>();
        SearchHit[] hits = null;
        Long total = null;
        try {
            // 8.调用方法进行数据通信
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            // 9.解析输出结果
            hits = searchResponse.getHits().getHits();

            total = searchResponse.getHits().getTotalHits().value;

            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                System.out.println("结果：" + sourceAsString);
                // 10.解析高亮结果
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField caseTittlDateUtilse = highlightFields.get("caseTittlDateUtilse");
                Text[] fragments = caseTittlDateUtilse.getFragments();
                for (Text fragment : fragments) {
                    System.err.println("高亮结果： " + fragment.toString());
//                    System.err.println("userId： " + JSON.parseObject(sourceAsString).get("id"));
                    SfwDto sfwDto = new SfwDto();
                    sfwDto.setCaseTittlDateUtilse(fragment.toString());
                    sfwDto.setNumber(JSON.parseObject(sourceAsString).get("number").toString());
                    sfwDto.setCaseUrl(JSON.parseObject(sourceAsString).get("caseUrl").toString());
                    sfwDto.setSubmissionTime(JSON.parseObject(sourceAsString).get("submissionTime").toString());
                    sfwDto.setCaseType(JSON.parseObject(sourceAsString).get("caseType").toString());
                    sfwDto.setVisits(Integer.valueOf(JSON.parseObject(sourceAsString).get("visits").toString()));
                    sfwDtoArrayList.add(sfwDto);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
//        return   CommonResult.success(searchResponse);
//        return CommonResult.success(Arrays.asList(hits));
//        System.out.println(sfwDtoArrayList);
//        return CommonResult.success(sfwDtoArrayList);
        res.put("page", page);
        res.put("size", size);
        res.put("total", total);
        res.put("dataList", sfwDtoArrayList);
        return CommonResult.success(res);
    }

    @ApiOperation(value = "高亮搜索，文章列表", notes = "")
    @PostMapping("/searchByKeyword")
    public CommonResult searchByKeyword(@RequestBody SearchReqDto searchReqDto) {
        Map<String, Object> resMap = searchUtil.highLightMatch(searchReqDto);

        return CommonResult.success(resMap);
    }
/*

    @ApiOperation(value = "高级组合查询", notes = "")
    @PostMapping("/boolSearch")
    @ResponseBody
    public CommonResult BoolSearch( @RequestBody List<CoreSearchReqDto> coreSearchReqDtoList) {
        Map<String, Object> resMap = searchUtil.BoolSearch(coreSearchReqDtoList);

        JsonResponse json = new JsonResponse();
        json.setData(resMap.get("searchResultList"));
        json.setTotal((Long) resMap.get("total"));
        return json;
    }

    *//**
     * 精确查询 搜索文章内容
     *//*
    @GetMapping("/termQuery")
    public CommonResult termQuery(@RequestParam("index") String index,
                                  @RequestParam("searchFiled") String searchFiled,
                                  @RequestParam("searchValue") String searchValue) throws IOException {
        SearchRepDto searchRepDto = searchUtil.termQuery(index, searchFiled, searchValue);
        if (!StringUtil.isNotEmpty(searchRepDto.getSourceAsString())) {
            if (index.equals("1") || index.equals("3")) {
                CaseInfoBean entity = this.getModelService().getById(searchValue);
                entity.setThumbnail(sysAttachInfoService.findSysAttachIds(entity.getCaseId(), "Attach002"));
                entity.setAnnex(sysAttachInfoService.findSysAttachIds(entity.getCaseId(), "Attach003"));
                entity.setAnnex1(sysAttachInfoService.findSysAttachIds(entity.getCaseId(), "Attach004"));
                entity.setFiles(sysAttachInfoService.findSysAttachIds(entity.getCaseId(), "Attach007"));
                searchRepDto.setSourceAsString(JSON.toJSON(entity));
            } else {
                PcontextInfoBean entity = this.pcontextInfoService.getById(searchValue);
                searchRepDto.setSourceAsString(JSON.toJSON(entity));
            }
        }

        JsonResponse json = new JsonResponse();
        json.setData(searchRepDto);
        return json;
    }

    *//**
     * 时间段数据统计
     *//*
    @GetMapping("/yearRangeQuery")
    public JsonResponse yearRangeQuery() throws IOException {
        Map<String, Object> resMap = searchUtil.yearRangeQuery();
        JsonResponse json = new JsonResponse();
        json.setTotal((Long) resMap.get("total"));
        json.setData(resMap);
        return json;
    }
    *//**
     * 地域数据统计
     *//*
    @GetMapping("/areaRangeQuery")
    public JsonResponse areaRangeQuery() throws IOException {
        Map<String, Object> resMap = searchUtil.areaRangeQuery();
        JsonResponse json = new JsonResponse();
        json.setTotal((Long) resMap.get("total"));
        json.setData(resMap);
        return json;
    }
    *//**
     * 类型数据统计
     *//*
    @GetMapping("/typeRangeQuery")
    public JsonResponse typeRangeQuery() throws IOException {
        Map<String, Object> resMap = searchUtil.typeRangeQuery();
        JsonResponse json = new JsonResponse();
        json.setTotal((Long) resMap.get("total"));
        json.setData(resMap);
        return json;
    }

    *//**
     * 机构数据统计
     *//*
    @GetMapping("/mechanismRangeQuery")
    public JsonResponse mechanismRangeQuery() throws IOException {
        Map<String, Object> resMap = searchUtil.mechanismRangeQuery();
        JsonResponse json = new JsonResponse();
        json.setTotal((Long) resMap.get("total"));
        json.setData(resMap);
        return json;
    }

    *//**
     * 其他字段分组数据统计
     *//*
    @GetMapping("/searchRange")
    public JsonResponse searchRange(@RequestParam(value = "rangeString") String rangeString,
                                    @RequestParam(value = "rangeType") Integer rangeType
    ) throws IOException {
        Map<String, Object> resMap = searchUtil.searchRangeQuery(rangeString,rangeType);
        JsonResponse json = new JsonResponse();
        json.setTotal((Long) resMap.get("total"));
        json.setData(resMap);
        return json;
    }






    *//**
     * 精确查询 搜索文章内容
     *//*
    @GetMapping("/matchDoc")
    @ApiOperation(value = "案例库导入", notes = "案例库")
    @ResponseBody
    public void matchDoc() {
        SearchRequest searchRequest = new SearchRequest("case_info");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();

        sourceBuilder.size(200);
        sourceBuilder.from(1);
        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                System.out.println("结果： " + sourceAsString);
                CaseInfoBean caseInfoBeans = JSONObject.parseObject(sourceAsString, CaseInfoBean.class);
                caseInfoBeans.setCaseId(null);
                caseInfoBeans.setTypeId("1452896229359554561");
                caseInfoBeans.setColumnId("1452896127173726210");
                caseInfoBeans.setPublishHair("1303987938859204609");
                caseInfoBeans.setIsPublish("1");
                caseInfoBeans.setPublishDate(DateUtil.getNowYMDHMSDate());
                caseInfoBeans.setUploadDate(DateUtil.getNowYMDHMSDate());
                caseInfoBeans.setApproveStart("SHZT02");
                caseInfoBeans.setApproveDate(DateUtil.getNowYMDHMSDate());
                this.getModelService().save(caseInfoBeans);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    *//**
     * 精确查询 搜索文章内容
     *//*
    @GetMapping("/lawDoc")
    @ApiOperation(value = "公法网导入", notes = "案例库")
    @ResponseBody
    public void lawDoc() {
        SearchRequest searchRequest = new SearchRequest("law_info");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();

        sourceBuilder.size(200);
        sourceBuilder.from(1);
        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                System.out.println("结果： " + sourceAsString);
                PcontextInfoBean caseInfoBeans = JSONObject.parseObject(sourceAsString, PcontextInfoBean.class);
                caseInfoBeans.setContextId(null);
                caseInfoBeans.setColumnId("1635155642122564284");
                caseInfoBeans.setPublishHair("1303987938859204609");
                caseInfoBeans.setIsPublish("1");
                caseInfoBeans.setPublishDate(DateUtil.getNowYMDHMSDate());
                caseInfoBeans.setAuditDate(DateUtil.getNowYMDHMSDate());
                caseInfoBeans.setAuditStart("SHZT01");
                this.pcontextInfoService.save(caseInfoBeans);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    *//**
     * 数据库同步ES（临时），线上logstash做全量canal做增量
     *//*
    @GetMapping("/tb_case")
    @ResponseBody
    public  void tb_case() throws IOException {
        List<Map<String, Object>> caseList= caseInfoService.selectEsCaseInfo();
        for (int i = 0; i <caseList.size() ; i++) {
            searchUtil.createDocument(caseList.get(i),"case_info_b");
        }

    }


    @GetMapping("/tb_law")
    @ResponseBody
    public  void tb_law() throws IOException {
        List<Map<String, Object>> caseList= caseInfoService.selectEsPublicInfo();
        for (int i = 0; i <caseList.size() ; i++) {
            searchUtil.createDocument(caseList.get(i),"law_info_b");
        }

    }*/

    /**
     *删除文档
     * @param id 数据库文档id
     * @param index_name 索引名称
     * @throws IOException
     */
    @GetMapping("/deleteDocument")
    @ResponseBody
    public  void deleteDocument(@RequestParam("id") String id,@RequestParam("index_name")String index_name) throws IOException {
        RestStatus restStatus= searchUtil.DeleteDocument(id,index_name);
        System.out.println(restStatus.getStatus());

    }


    /**
     * 添加坐标点
     * @param user
     * @return
     */
    @PostMapping("/addESPoint")
    public CommonResult addESPoint(@RequestBody User user) throws IOException {

        Integer randomId = new Random().nextInt(1000000);
        user.setUserId(Long.valueOf(randomId));

        //创建请求
        IndexRequest request = new IndexRequest("test");
        request.id();//不设置自动
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
        //  我们的数据放入请求json将
        request.source(JSON.toJSONString(user), XContentType.JSON);
//        客户端发送请求,获取响应的结果
        IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
        System.out.println(indexResponse.toString());//返回这行记录（doc）
        System.out.println(indexResponse.status());

        return CommonResult.success();
    }

    /**
     * 矩阵搜索
     * @param geoBoundingBoxEntity
     * @return
     */
    @PostMapping("/geoBoundingBox")
    public CommonResult geoBoundingBox(
            @RequestBody GeoBoundingBoxEntity geoBoundingBoxEntity) throws IOException {

        GeoBoundingBoxQueryBuilder queryBuilder = QueryBuilders.geoBoundingBoxQuery("geo")
                .setCorners( // 设置矩形坐标
                        new GeoPoint(40.04917820795009, 115.95959861307438), // 设置矩形的左上角坐标
                        new GeoPoint(39.848402544660985, 116.54755519845526) // 设置矩形的右下角坐标
                );
//        .setCorners(
//                geoBoundingBoxEntity.getTopLeft(),
//                geoBoundingBoxEntity.getBottomRight()
//        );

        SearchRequest searchRequest = new SearchRequest("test");



        SearchSourceBuilder builder = new SearchSourceBuilder();


        builder.query(queryBuilder);

        searchRequest.source(builder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.解析输出结果
        List<User> userList = new ArrayList<>();

        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            System.out.println("结果： " + sourceAsString);
            User  user =JSON.parseObject(sourceAsString,User.class);
            userList.add(user);
        }

        return CommonResult.success(userList);
    }

    /**
     * 类似附近好友查询
     * @param centerPoint
     * @param km
     * @return
     */
    @PostMapping("/geoDistance")
    public CommonResult geoDistance(  @RequestBody  GeoPoint centerPoint, String km) throws IOException {

        GeoDistanceQueryBuilder queryBuilder = QueryBuilders.geoDistanceQuery("geo")
//                .distance("1km") //设置搜索距离为1千米
                .distance(km, DistanceUnit.KILOMETERS)
// 设置当前位置
//         .point(new GeoPoint(40.0171214752916, 116.39351697849565));
                        .point(centerPoint);
        SearchRequest searchRequest = new SearchRequest("test");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.query(queryBuilder);

        GeoDistanceSortBuilder geoDistanceSortBuilder = SortBuilders.geoDistanceSort("geo", new GeoPoint(40.0171214752916, 116.39351697849565));

        geoDistanceSortBuilder.order(SortOrder.ASC);
        searchSourceBuilder.sort(geoDistanceSortBuilder);

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        List<User> userList = new ArrayList<>();

        // 7.解析输出结果
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            System.out.println("结果： " + sourceAsString);
            User  user =JSON.parseObject(sourceAsString,User.class);
            userList.add(user);
        }

        return CommonResult.success(userList);
    }

    @GetMapping("/maping")
    public void maping_case() throws IOException {
        // 判断index 是否存在
        GetIndexRequest getIndexRequest = new GetIndexRequest("sf_case_homology");
        boolean exit = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
        System.out.println(exit + "-----------------");
        CreateIndexRequest createIndexRequest = null;
        if (!exit) {
            createIndexRequest = new CreateIndexRequest("sf_case_homology");
        }

        //设置参数 分片和副本
//        createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));

        //指定映射

        Map<String, Object> homologyId = new HashMap<>();
        homologyId.put("type", "keyword");

        Map<String, Object> homologyTittle = new HashMap<>();
        homologyTittle.put("type", "text");

        Map<String, Object> homologyType = new HashMap<>();
        homologyType.put("type", "text");

        Map<String, Object> properties = new HashMap<>();
        properties.put("homologyId", homologyId);
        properties.put("homologyTittle", homologyTittle);
        properties.put("homologyType", homologyType);


        Map<String, Object> mapping = new HashMap<>();
        mapping.put("properties", properties);
        createIndexRequest.mapping(mapping);

        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
//        先创建索引，单独指定maping
       /* PutMappingRequest putMappingRequest=new PutMappingRequest(JSON.toJSONString(new User()), XContentType.JSON);
        AcknowledgedResponse acknowledgedResponse = client.indices().putMapping(putMappingRequest);*/

        System.out.println(createIndexResponse);

    }


}
